using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using DnsService.Interfaces;
using DnsService.Models;
using NLog;

namespace DnsService.Services
{
    /// <summary>
    /// DNS配置管理器
    /// </summary>
    /// <remarks>
    /// 作者：huobing
    /// 功能：管理DNS服务的配置文件，包括加载、保存和监控配置文件变化
    /// </remarks>
    public class DnsConfigManager : IDnsConfigManager, IDisposable
    {
        private readonly string _configFilePath = "Conf/DNSService.conf";
        private FileSystemWatcher? _fileWatcher;
        private bool _isWatching = false;
        private bool _disposed = false;
        private DnsServiceConfig? _config;
        private readonly Logger _logger = LogManager.GetCurrentClassLogger();

        /// <summary>
        /// 获取当前配置对象
        /// </summary>
        public DnsServiceConfig Config => _config ??= LoadConfig();

        /// <summary>
        /// 配置文件变更事件
        /// </summary>
        public event EventHandler? ConfigFileChanged;

        /// <summary>
        /// 构造函数
        /// </summary>
        public DnsConfigManager()
        {
            _config = LoadConfig();
        }

        /// <summary>
        /// 加载配置文件
        /// </summary>
        /// <returns>DNS服务配置</returns>
        public DnsServiceConfig LoadConfig()
        {
            var config = new DnsServiceConfig();

            if (!File.Exists(_configFilePath))
            {
                // 如果配置文件不存在，创建默认配置
                SaveConfig(config);
                return config;
            }

            try
            {
                var lines = File.ReadAllLines(_configFilePath);
                
                foreach (var line in lines)
                {
                    // 跳过空行和注释
                    if (string.IsNullOrWhiteSpace(line) || line.TrimStart().StartsWith("#"))
                        continue;

                    // 解析key=value格式
                    var parts = line.Split('=', 2);
                    if (parts.Length == 2)
                    {
                        var key = parts[0].Trim();
                        var value = parts[1].Trim();

                        ParseConfigValue(config, key, value);
                    }
                }
            }
            catch (Exception ex)
            {
                _logger?.Error(ex, $"加载配置文件失败: {ex.Message}");
                // 返回默认配置
                return new DnsServiceConfig();
            }

            return config;
        }

        /// <summary>
        /// 保存配置文件
        /// </summary>
        /// <param name="config">DNS服务配置</param>
        public void SaveConfig(DnsServiceConfig config)
        {
            try
            {
                var configContent = GenerateKeyValueConfig(config);
                
                // 确保目录存在
                var directory = Path.GetDirectoryName(_configFilePath);
                if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
                {
                    Directory.CreateDirectory(directory);
                }
                
                File.WriteAllText(_configFilePath, configContent);
                _logger?.Info($"配置文件已保存: {_configFilePath}");
            }
            catch (Exception ex)
            {
                _logger?.Error(ex, $"保存配置文件失败: {ex.Message}");
                throw;
            }
        }

        /// <summary>
        /// 解析配置值
        /// </summary>
        /// <param name="config">配置对象</param>
        /// <param name="key">配置键</param>
        /// <param name="value">配置值</param>
        private static void ParseConfigValue(DnsServiceConfig config, string key, string value)
        {
            switch (key.ToLowerInvariant())
            {
                case "isenabled":
                    config.IsEnabled = bool.TryParse(value, out bool isEnabled) && isEnabled;
                    break;
                case "port":
                    config.Port = int.TryParse(value, out int port) ? port : 53;
                    break;
                case "upstreamdnsservers":
                    config.UpstreamDnsServers = [.. value.Split(',')
                        .Select(s => s.Trim())
                        .Where(s => !string.IsNullOrEmpty(s))];
                    break;
                case "enablecache":
                    config.EnableCache = !bool.TryParse(value, out bool enableCache) || enableCache;
                    break;
                case "cacheexpirationminutes":
                    config.CacheExpirationMinutes = int.TryParse(value, out int expiration) ? expiration : 30;
                    break;
                case "recordfilepath":
                    config.RecordFilePath = value;
                    break;
                case "maxconnections":
                    if (int.TryParse(value, out int maxConnections)) config.MaxConnections = maxConnections;
                    break;
                case "enablesocketmanagement":
                    if (bool.TryParse(value, out bool enableSocket)) config.EnableSocketManagement = enableSocket;
                    break;
                case "socketmanagementport":
                    if (int.TryParse(value, out int socketPort)) config.SocketManagementPort = socketPort;
                    break;
                case "enablerecordpersistence":
                    if (bool.TryParse(value, out bool enablePersistence)) config.EnableRecordPersistence = enablePersistence;
                    break;
                case "enableaccesscontrol":
                    if (bool.TryParse(value, out bool enableAccess)) config.EnableAccessControl = enableAccess;
                    break;
                case "allowedips":
                    config.AllowedIPs = [.. value.Split(',')
                        .Select(s => s.Trim())
                        .Where(s => !string.IsNullOrEmpty(s))];
                    break;
                case "enablewildcardresolution":
                    config.EnableWildcardResolution = !bool.TryParse(value, out bool enableWildcard) || enableWildcard;
                    break;
                case "forwardrecordfilepath":
                    config.ForwardRecordFilePath = value;
                    break;
                case "reverserecordfilepath":
                    config.ReverseRecordFilePath = value;
                    break;
                case "dnsrecordconfigwatchinterval":
                    config.DnsRecordConfigWatchInterval = int.TryParse(value, out int watch) ? watch : 30;
                    break;
                case "defaultrecordttl":
                    config.DefaultRecordTtl = int.TryParse(value, out int ttl) ? ttl : 3600;
                    break;
                default:
                    // 忽略未知的配置项
                    break;
            }
        }
        
        /// <summary>
        /// 生成key=value格式的配置文件内容
        /// </summary>
        /// <param name="config">DNS服务配置</param>
        /// <returns>配置文件内容</returns>
        private static string GenerateKeyValueConfig(DnsServiceConfig config)
        {
            var lines = new List<string>()
            {
                "# DNS服务配置文件",
                "# 格式：key=value",
                "# 注释以#开头",
                "",
                "# 服务基本配置",
                "# 是否启用DNS服务",
                $"IsEnabled={config.IsEnabled}",
                "",
                "# DNS服务监听端口",
                $"Port={config.Port}",
                "",
                "# 上游DNS服务器列表（多个服务器用逗号分隔）",
                $"UpstreamDnsServers={string.Join(",", config.UpstreamDnsServers ?? [])}",
                "",
                "# 缓存配置",
                "# 是否启用DNS缓存",
                $"EnableCache={config.EnableCache}",
                "",
                "# 缓存过期时间（分钟）",
                $"CacheExpirationMinutes={config.CacheExpirationMinutes}",
                "",
                "# 日志系统已迁移到NLog，请通过nlog.config文件配置日志行为",
                "",
                "",
                "",
                "",
                "",
                "",
                "",
                "",
                "# 记录文件路径",
                $"RecordFilePath={config.RecordFilePath ?? "dns.conf"}",
                "",
                "# 安全配置",
                $"EnableAccessControl={config.EnableAccessControl}",
                $"AllowedIPs={string.Join(",", config.AllowedIPs ?? [])}",
                "",
                "# 正向/反向记录配置",
                $"EnableWildcardResolution={config.EnableWildcardResolution}",
                "",
                "# 正向配置文件路径",
                $"ForwardRecordFilePath={config.ForwardRecordFilePath ?? "Conf/dns.conf"}",
                "",
                "# 反向配置文件路径",
                $"ReverseRecordFilePath={config.ReverseRecordFilePath ?? "Conf/dns_reverse.conf"}",
                "",
                "# dns记录配置文件监控间隔（秒）",
                $"DnsRecordConfigWatchInterval={config.DnsRecordConfigWatchInterval}",
                "",
                "# 默认DNS记录TTL（秒）",
                $"DefaultRecordTtl={config.DefaultRecordTtl}"
            };
            
            return string.Join(Environment.NewLine, lines);
        }

        /// <summary>
        /// 开始监控配置文件变化
        /// </summary>
        public void StartWatching()
        {
            if (_isWatching) return;
            
            try
            {
                var directory = Path.GetDirectoryName(_configFilePath) ?? ".";
                var fileName = Path.GetFileName(_configFilePath);
                
                _fileWatcher = new FileSystemWatcher(directory, fileName)
                {
                    NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.Size,
                    EnableRaisingEvents = true
                };
                
                _fileWatcher.Changed += OnConfigFileChanged;
                _isWatching = true;
                
                _logger?.Info($"开始监控配置文件: {_configFilePath}");
            }
            catch (Exception ex)
            {
                _logger?.Error(ex, $"启动配置文件监控失败: {ex.Message}");
            }
        }
        
        /// <summary>
        /// 停止监控配置文件变化
        /// </summary>
        public void StopWatching()
        {
            if (!_isWatching || _fileWatcher == null) return;
            
            _fileWatcher.EnableRaisingEvents = false;
            _fileWatcher.Changed -= OnConfigFileChanged;
            _fileWatcher.Dispose();
            _fileWatcher = null;
            _isWatching = false;
            
            _logger?.Info($"停止监控配置文件: {_configFilePath}");
        }
        
        /// <summary>
        /// 配置文件变更事件处理
        /// </summary>
        /// <param name="sender">事件源</param>
        /// <param name="e">事件参数</param>
        private void OnConfigFileChanged(object sender, FileSystemEventArgs e)
        {
            try
            {
                // 延迟处理，避免文件被占用
                System.Threading.Thread.Sleep(100);
                
                // 重新加载配置
                LoadConfig();
                
                // 触发配置变更事件
                ConfigFileChanged?.Invoke(this, EventArgs.Empty);
                
                _logger?.Debug($"配置文件已更新: {_configFilePath}");
            }
            catch (Exception ex)
            {
                _logger?.Error(ex, $"处理配置文件变更失败: {ex.Message}");
            }
        }

        /// <summary>
        /// 获取设置值
        /// </summary>
        /// <param name="key">设置键</param>
        /// <param name="defaultValue">默认值</param>
        /// <returns>设置值</returns>
        public string GetSetting(string key, string defaultValue = "")
        {
            var config = LoadConfig();

            return key.ToLowerInvariant() switch
            {
                "port" => config.Port.ToString(),
                "upstreamdnsservers" => string.Join(",", config.UpstreamDnsServers ?? []),
                "enablecache" => config.EnableCache.ToString(),
                "cacheexpirationminutes" => config.CacheExpirationMinutes.ToString(),


                "recordfilepath" => config.RecordFilePath ?? defaultValue,
                "maxconnections" => config.MaxConnections.ToString(),
                "enablesocketmanagement" => config.EnableSocketManagement.ToString(),
                "socketmanagementport" => config.SocketManagementPort.ToString(),
                "enablerecordpersistence" => config.EnableRecordPersistence.ToString(),
                "enableaccesscontrol" => config.EnableAccessControl.ToString(),
                "allowedips" => string.Join(",", config.AllowedIPs ?? []),

                "enablewildcardresolution" => config.EnableWildcardResolution.ToString(),
                "forwardrecordfilepath" => config.ForwardRecordFilePath ?? defaultValue,
                "reverserecordfilepath" => config.ReverseRecordFilePath ?? defaultValue,
                "dnsrecordconfigwatchinterval" => config.DnsRecordConfigWatchInterval.ToString(),
                "defaultrecordttl" => config.DefaultRecordTtl.ToString(),
                _ => defaultValue,
            };
        }

        /// <summary>
        /// 保存设置值
        /// </summary>
        /// <param name="key">设置键</param>
        /// <param name="value">设置值</param>
        public void SaveSetting(string key, string value)
        {
            var config = LoadConfig();
            
            switch (key.ToLowerInvariant())
            {
                case "port":
                    if (int.TryParse(value, out int port)) config.Port = port;
                    break;
                case "upstreamdnsservers":
                    config.UpstreamDnsServers = [.. value.Split(',')
                        .Select(s => s.Trim())
                        .Where(s => !string.IsNullOrEmpty(s))];
                    break;
                case "enablecache":
                    if (bool.TryParse(value, out bool enableCache)) config.EnableCache = enableCache;
                    break;
                case "cacheexpirationminutes":
                    if (int.TryParse(value, out int expiration)) config.CacheExpirationMinutes = expiration;
                    break;
                case "recordfilepath":
                    config.RecordFilePath = value;
                    break;

                case "maxconnections":
                    config.MaxConnections = int.TryParse(value, out int maxConnections) ? maxConnections : 100;
                    break;
                case "enablesocketmanagement":
                    config.EnableSocketManagement = bool.TryParse(value, out bool enableSocket) && enableSocket;
                    break;
                case "socketmanagementport":
                    config.SocketManagementPort = int.TryParse(value, out int socketPort) ? socketPort : 8053;
                    break;
                case "enablerecordpersistence":
                    config.EnableRecordPersistence = !bool.TryParse(value, out bool enablePersistence) || enablePersistence;
                    break;
                case "enableaccesscontrol":
                    config.EnableAccessControl = bool.TryParse(value, out bool enableAccess) && enableAccess;
                    break;
                case "allowedips":
                    config.AllowedIPs = [.. value.Split(',')
                        .Select(s => s.Trim())
                        .Where(s => !string.IsNullOrEmpty(s))];
                    break;
                case "enablewildcardresolution":
                    if (bool.TryParse(value, out bool enableWildcard)) config.EnableWildcardResolution = enableWildcard;
                    break;
                case "forwardrecordfilepath":
                    config.ForwardRecordFilePath = value;
                    break;
                case "reverserecordfilepath":
                    config.ReverseRecordFilePath = value;
                    break;
                case "dnsrecordconfigwatchinterval":
                    if (int.TryParse(value, out int watch)) config.DnsRecordConfigWatchInterval = watch;
                    break;
                case "defaultrecordttl":
                    if (int.TryParse(value, out int ttl)) config.DefaultRecordTtl = ttl;
                    break;
            }
            
            SaveConfig(config);
        }

        /// <summary>
        /// 获取本地DNS服务端口
        /// </summary>
        /// <returns>端口号</returns>
        public int GetLocalDnsPort()
        {
            return LoadConfig().Port;
        }

        /// <summary>
        /// 设置本地DNS服务端口
        /// </summary>
        /// <param name="port">端口号</param>
        /// <returns>是否设置成功</returns>
        public bool SetLocalDnsPort(int port)
        {
            var config = LoadConfig();
            config.Port = port;
            SaveConfig(config);
            return true;
        }

        /// <summary>
        /// 获取上游DNS服务器列表
        /// </summary>
        /// <returns>DNS服务器列表</returns>
        public List<string> GetUpstreamDnsServers()
        {
            return LoadConfig().UpstreamDnsServers ?? [];
        }

        /// <summary>
        /// 添加上游DNS服务器
        /// </summary>
        /// <param name="dnsServer">DNS服务器地址</param>
        /// <returns>是否添加成功</returns>
        public bool AddUpstreamDnsServer(string dnsServer)
        {
            var config = LoadConfig();
            config.UpstreamDnsServers ??= [];
            
            if (!config.UpstreamDnsServers.Contains(dnsServer))
            {
                config.UpstreamDnsServers.Add(dnsServer);
                SaveConfig(config);
                return true;
            }
            return false;
        }

        /// <summary>
        /// 移除上游DNS服务器
        /// </summary>
        /// <param name="dnsServer">DNS服务器地址</param>
        /// <returns>是否移除成功</returns>
        public bool RemoveUpstreamDnsServer(string dnsServer)
        {
            var config = LoadConfig();
            if (config.UpstreamDnsServers?.Remove(dnsServer) == true)
            {
                SaveConfig(config);
                return true;
            }
            return false;
        }

        /// <summary>
        /// 获取DNS记录字典
        /// </summary>
        /// <returns>DNS记录字典</returns>
        public Dictionary<string, DnsRecord> GetDnsRecords()
        {
            return LoadConfig().DnsRecords ?? [];
        }

        /// <summary>
        /// 添加DNS记录
        /// </summary>
        /// <param name="domain">域名</param>
        /// <param name="ip">IP地址</param>
        /// <param name="recordType">记录类型</param>
        /// <param name="ttl">生存时间</param>
        /// <param name="description">描述信息</param>
        /// <returns>是否添加成功</returns>
        public bool AddDnsRecord(string domain, string ip, string recordType = "A", int ttl = 3600, string description = "")
        {
            var config = LoadConfig();
            config.DnsRecords ??= [];
            
            var record = new DnsRecord
            {
                Domain = domain,
                IP = ip,
                RecordType = recordType,
                Ttl = ttl,
                Description = description
            };
            
            config.DnsRecords[domain] = record;
            SaveConfig(config);
            return true;
        }

        /// <summary>
        /// 移除DNS记录
        /// </summary>
        /// <param name="domain">域名</param>
        /// <returns>是否移除成功</returns>
        public bool RemoveDnsRecord(string domain)
        {
            var config = LoadConfig();
            if (config.DnsRecords?.Remove(domain) == true)
            {
                SaveConfig(config);
                return true;
            }
            return false;
        }

        /// <summary>
        /// 获取是否启用DNS缓存
        /// </summary>
        /// <returns>是否启用缓存</returns>
        public bool GetEnableCache()
        {
            return LoadConfig().EnableCache;
        }

        /// <summary>
        /// 设置是否启用DNS缓存
        /// </summary>
        /// <param name="enable">是否启用</param>
        /// <returns>是否设置成功</returns>
        public bool SetEnableCache(bool enable)
        {
            var config = LoadConfig();
            config.EnableCache = enable;
            SaveConfig(config);
            return true;
        }

        /// <summary>
        /// 获取缓存过期时间（分钟）
        /// </summary>
        /// <returns>缓存过期时间</returns>
        public int GetCacheExpirationMinutes()
        {
            return LoadConfig().CacheExpirationMinutes;
        }

        /// <summary>
        /// 设置缓存过期时间（分钟）
        /// </summary>
        /// <param name="minutes">过期时间</param>
        /// <returns>是否设置成功</returns>
        public bool SetCacheExpirationMinutes(int minutes)
        {
            var config = LoadConfig();
            config.CacheExpirationMinutes = minutes;
            SaveConfig(config);
            return true;
        }
        
        /// <summary>
        /// 获取默认DNS记录TTL（秒）
        /// </summary>
        /// <returns>默认TTL值</returns>
        public int GetDefaultRecordTtl()
        {
            return LoadConfig().DefaultRecordTtl;
        }
        
        /// <summary>
        /// 设置默认DNS记录TTL（秒）
        /// </summary>
        /// <param name="ttl">TTL值（秒）</param>
        /// <returns>是否设置成功</returns>
        public bool SetDefaultRecordTtl(int ttl)
        {
            var config = LoadConfig();
            config.DefaultRecordTtl = ttl;
            SaveConfig(config);
            return true;
        }


        /// <summary>
        /// 获取是否启用日志记录
        /// </summary>
        /// <summary>
        /// 重置为默认配置
        /// </summary>
        /// <returns>是否重置成功</returns>
        public bool ResetToDefaults()
        {
            var defaultConfig = new DnsServiceConfig();
            SaveConfig(defaultConfig);
            return true;
        }

        /// <summary>
        /// 释放资源
        /// </summary>
        /// <param name="disposing">是否释放托管资源</param>
        protected virtual void Dispose(bool disposing)
        {
            if (!_disposed)
            {
                if (disposing)
                {
                    // 释放托管资源
                    StopWatching();
                }
                
                _disposed = true;
            }
        }

        /// <summary>
        /// 析构函数
        /// </summary>
        ~DnsConfigManager()
        {
            Dispose(false);
        }

        /// <summary>
        /// 实现IDisposable接口
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
    }
}